﻿using Platformer_Example.Controller.Input;
using Platformer_Example.Controller.Terrain;
using System;
using Transformable_Engine_v2.Engine;
using Transformable_Engine_v2.Engine.GameObjects.Containers;
using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace Platformer_Example.Controller.Character.Behavior
{
    public class BaseBehavior : Container
    {
        public BaseInputCharacter Character { get; set; }

        #region Attack State
        public virtual void UpdateAttackState(TimeSpan gameTime)
        {
            
        }

        public virtual void EndAttack()
        {
            Character.ChangeState(BaseInputCharacter.State.Idle);
        }

        public virtual void OnKeyPressAttack(InputState.Key key)
        {
        }

        public virtual void OnKeyReleaseAttack(InputState.Key key)
        {
        }
        #endregion

        #region Fall State
        public virtual void UpdateFallState(TimeSpan gameTime)
        {
            Character.ChangeDirectionFromInput();
            Character.ChangeWalkSpeedFromInput();

            Character.ApplyGravity(gameTime);

            Character.ApplyMovementX(gameTime);
            if (Character.ApplyMovementY(gameTime, true) == BaseTerrain.TerrainType.Floor)
                Character.ChangeState(BaseInputCharacter.State.Idle);

            Character.ApplyWarps();

            if (Character.InputListener.KeyState[InputState.Key.ButtonWest])
            {
                if (Character.IsCarryingObject)
                {
                    Character.ChangeState(BaseInputCharacter.State.AirThrow);
                }
            }
        }

        public virtual void OnKeyPressFall(InputState.Key key)
        {
            switch (key)
            {
                case InputState.Key.Up:
                case InputState.Key.Down:
                    //Check for ladders
                    var ladder = Character.CurrentMap.CollidingWithLadder(Character.GetLadderCollisionArea());
                    if (ladder != null && !Character.IsCarryingObject)
                    {
                        Character.CurrentLadder = ladder;
                        Character.ChangeState(BaseInputCharacter.State.LadderIdle);
                    }
                    break;
            }
        }

        public virtual void OnKeyReleaseFall(InputState.Key key)
        {
        }
        #endregion

        #region Idle State
        public virtual void UpdateIdleState(TimeSpan gameTime)
        {
            Character.ApplyGravity(gameTime);

            Character.ApplyMovementX(gameTime);
            if (Character.ApplyMovementY(gameTime, false) == BaseTerrain.TerrainType.None)
            {
                Character.ResetGravityX();
                Character.ResetGravityY();
                Character.ChangeState(BaseInputCharacter.State.Fall);
            }
            else if (Character.InputListener.KeyState[InputState.Key.Left] || Character.InputListener.KeyState[InputState.Key.Right])
                Character.ChangeState(BaseInputCharacter.State.Walk);
            else if (Character.InputListener.KeyState[InputState.Key.ButtonWest])
            {
                if (Character.IsCarryingObject)
                {
                    Character.ChangeState(BaseInputCharacter.State.Throw);
                }
                else
                {
                    var pickedItem = Character.CurrentMap.CanPickupItem(Character.GetPickupCollisionArea());

                    if (pickedItem != null)
                    {
                        Character.PickUpObject(pickedItem.GetThrowableObject());
                        Character.ChangeState(BaseInputCharacter.State.Pickup);
                    }
                    else
                    {
                        Character.ChangeState(BaseInputCharacter.State.Attack);
                    }
                }
            }
                
        }

        public virtual void OnKeyPressIdle(InputState.Key key)
        {
            switch (key)
            {
                case InputState.Key.Up:
                case InputState.Key.Down:
                    //Check for ladders
                    var ladder = Character.CurrentMap.CollidingWithLadder(Character.GetLadderCollisionArea());
                    if (ladder != null && !Character.IsCarryingObject)
                    {
                        Character.CurrentLadder = ladder;
                        Character.ChangeState(BaseInputCharacter.State.LadderIdle);
                    }
                    break;
                case InputState.Key.ButtonSouth:
                    Character.ChangeState(BaseInputCharacter.State.Jump);
                    break;
            }
        }

        public virtual void OnKeyReleaseIdle(InputState.Key key)
        {

        }
        #endregion

        #region LadderClimb State
        public virtual void UpdateLadderClimbState(TimeSpan gameTime)
        {
            if (Character.InputListener.KeyState[InputState.Key.Up])
            {
                Character.AddToAbsolutePosition(-Character.LadderClimbSpeed * gameTime.TotalSeconds);
                if (Character.GetAbsolutePosition().Y < Character.CurrentLadder.Top + Game.Options.GridSize)
                {
                    Character.MoveAbsolute(new TE_Vector2(Character.GetAbsolutePosition().X, Character.CurrentLadder.Top + Game.Options.GridSize));
                }
            }
            else if (Character.InputListener.KeyState[InputState.Key.Down])
            {
                var positionOffset = Character.LadderClimbSpeed * gameTime.TotalSeconds;

                if (Character.GetAbsolutePosition().Y + positionOffset.Y > Character.CurrentLadder.Bottom)
                {
                    Character.MoveAbsolute(new TE_Vector2(Character.GetAbsolutePosition().X, Character.CurrentLadder.Bottom));
                    Character.ChangeState(BaseInputCharacter.State.Fall);
                }
                else
                    Character.AddToAbsolutePosition(Character.LadderClimbSpeed * gameTime.TotalSeconds);
            }
            else
            {
                Character.ChangeState(BaseInputCharacter.State.LadderIdle);
            }

            Character.ApplyWarps();
        }

        public virtual void OnKeyReleaseLadderClimb(InputState.Key key)
        {
        }

        public virtual void OnKeyPressLadderClimb(InputState.Key key)
        {
            switch (key)
            {
                case InputState.Key.Left:
                case InputState.Key.Right:
                    if (!Character.CurrentMap.IsCollidingWithForegroundWall(Character.CollisionArea))
                    {
                        Character.ResetGravityX();
                        Character.ResetGravityY();
                        Character.ChangeState(BaseInputCharacter.State.Fall);
                    }
                    break;
                case InputState.Key.ButtonSouth:
                    if (!Character.CurrentMap.IsCollidingWithForegroundWall(Character.CollisionArea))
                        Character.ChangeState(BaseInputCharacter.State.Jump);
                    break;
            }
        }
        #endregion

        #region LadderIdle State
        public virtual void UpdateLadderIdleState(TimeSpan gameTime)
        {
            if (Character.InputListener.KeyState[InputState.Key.Up] || Character.InputListener.KeyState[InputState.Key.Down])
            {
                Character.ChangeState(BaseInputCharacter.State.LadderClimb);
            }
        }

        public virtual void OnKeyPressLadderIdle(InputState.Key key)
        {
            switch (key)
            {
                case InputState.Key.Left:
                case InputState.Key.Right:
                    if (!Character.CurrentMap.IsCollidingWithForegroundWall(Character.CollisionArea))
                    {
                        Character.ResetGravityX();
                        Character.ResetGravityY();
                        Character.ChangeState(BaseInputCharacter.State.Fall);
                    }
                    break;
                case InputState.Key.ButtonSouth:
                    if (!Character.CurrentMap.IsCollidingWithForegroundWall(Character.CollisionArea))
                        Character.ChangeState(BaseInputCharacter.State.Jump);
                    break;
            }
        }

        public virtual void OnKeyReleaseLadderIdle(InputState.Key key)
        {
            
        }
        #endregion

        #region Walk State
        public virtual void UpdateWalkState(TimeSpan gameTime)
        {
            Character.ChangeDirectionFromInput();
            Character.ChangeWalkSpeedFromInput();

            Character.ApplyGravity(gameTime);

            Character.ApplyMovementX(gameTime);
            if (Character.ApplyMovementY(gameTime, false) != BaseTerrain.TerrainType.Floor)
            {
                Character.ResetGravityX();
                Character.ResetGravityY();
                Character.ChangeState(BaseInputCharacter.State.Fall);
            }

            if (!Character.InputListener.KeyState[InputState.Key.Left] &&
                !Character.InputListener.KeyState[InputState.Key.Right])
                Character.ChangeState(BaseInputCharacter.State.Idle);
            else if (Character.InputListener.KeyState[InputState.Key.ButtonWest])
            {
                if (Character.IsCarryingObject)
                {
                    Character.ChangeState(BaseInputCharacter.State.LongThrow);
                }
                else
                {
                    var pickedItem = Character.CurrentMap.CanPickupItem(Character.GetPickupCollisionArea());

                    if (pickedItem != null)
                    {
                        Character.PickUpObject(pickedItem.GetThrowableObject());
                        Character.ChangeState(BaseInputCharacter.State.Pickup);
                    }
                    else
                    {
                        Character.ChangeState(BaseInputCharacter.State.Attack);
                    }
                }
            }

            Character.ApplyWarps();
        }

        public virtual void OnKeyPressWalk(InputState.Key key)
        {
            switch (key)
            {
                case InputState.Key.Up:
                case InputState.Key.Down:
                    //Check for ladders
                    var ladder = Character.CurrentMap.CollidingWithLadder(Character.GetLadderCollisionArea());
                    if (ladder != null && !Character.IsCarryingObject)
                    {
                        Character.CurrentLadder = ladder;
                        Character.ChangeState(BaseInputCharacter.State.LadderIdle);
                    }
                    break;
                case InputState.Key.ButtonSouth:
                    Character.ChangeState(BaseInputCharacter.State.Jump);
                    break;
            }
        }

        public virtual void OnKeyReleaseWalk(InputState.Key key)
        {

        }
        #endregion

        #region Jump State
        public virtual void OnKeyReleaseJump(InputState.Key key)
        {

        }

        public virtual void OnKeyPressJump(InputState.Key key)
        {
            switch (key)
            {
                case InputState.Key.Up:
                case InputState.Key.Down:
                    //Check for ladders
                    var ladder = Character.CurrentMap.CollidingWithLadder(Character.GetLadderCollisionArea());
                    if (ladder != null && !Character.IsCarryingObject)
                    {
                        Character.CurrentLadder = ladder;
                        Character.ChangeState(BaseInputCharacter.State.LadderIdle);
                    }
                    break;
            }
        }

        public virtual void UpdateJumpState(TimeSpan gameTime)
        {
            
        }
        #endregion

        public void InitializeIdleState()
        {
            Character.ResetMovement();
            Character.ResetJumpCount();
        }

        public void InitializeWalkState()
        {
            
        }

        public void InitializeJumpState()
        {
            if (Character.JumpCount < 1)
                Character.JumpCount = 1;

            Character.Jump(Character.JumpHeight);
        }

        public void InitializeFallState()
        {
        }

        public void InitializeAttackState()
        {
            
        }

        public void InitializeLadderClimbState()
        {
            
        }

        public void InitializeLadderIdleState()
        {
            Character.MoveAbsolute(new TE_Vector2(Character.CurrentLadder.CenterMiddle.X, Character.GetAbsolutePosition().Y));
            Character.ResetJumpCount();
        }

        public void OnKeyPressPickup(InputState.Key key)
        {
        }

        public void OnKeyPressThrow(InputState.Key key)
        {
        }

        public void OnKeyPressLongThrow(InputState.Key key)
        {
        }

        public void OnKeyPressAirThrow(InputState.Key key)
        {
        }

        public void UpdatePickupState(TimeSpan gameTime)
        {
        }

        public void UpdateThrowState(TimeSpan gameTime)
        {
        }

        public void UpdateLongThrowState(TimeSpan gameTime)
        {
        }

        public void UpdateAirThrowState(TimeSpan gameTime)
        {
            Character.ChangeDirectionFromInput();
            Character.ChangeWalkSpeedFromInput();

            Character.ApplyGravity(gameTime);

            Character.ApplyMovementX(gameTime);
            Character.ApplyMovementY(gameTime, true);
        }

        public void OnKeyReleasePickup(InputState.Key key)
        {
            
        }

        public void OnKeyReleaseThrow(InputState.Key key)
        {
            
        }

        public void OnKeyReleaseLongThrow(InputState.Key key)
        {
            
        }

        public void OnKeyReleaseAirThrow(InputState.Key key)
        {
            
        }

        public void InitializeAirThrowState()
        {
            
        }

        public void InitializeThrowState()
        {
            
        }

        public void InitializeLongThrowState()
        {
            
        }

        public void InitializePickupState()
        {
            
        }
    }
}